package com.sjr.easy.chat.app.ws;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONException;
import com.google.common.collect.Maps;
import com.sjr.easy.chat.app.dto.AppTokenInfo;
import com.sjr.easy.chat.app.utils.AppTokenManager;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.PongMessage;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.util.List;
import java.util.Map;

@Slf4j
@Component
public class AppTextWebSocketHandler extends TextWebSocketHandler implements InitializingBean {

    @Autowired
    private List<TextMessageProcessor> textMessageProcessorList;

    @Autowired
    private AppTokenManager appTokenManager;

    @Autowired
    private WSConnectionManager wsConnectionManager;

    private final Map<String, TextMessageProcessor> textMessageProcessorMap = Maps.newHashMap();


    private static final String WS_SESSION_ATTR_USER_ID_KEY = "_WS_SESSION_ATTR_USER_ID_KEY_";

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        HttpHeaders httpHeaders = session.getHandshakeHeaders();
        String token = httpHeaders.getFirst("token");
        if (StringUtils.isEmpty(token)) {
            log.error("用户未登录");
            session.close();
            return;
        }
        AppTokenInfo tokenInfo = appTokenManager.getTokenInfo(token);
        if (tokenInfo == null) {
            log.error("token失效");
            return;
        }
        Long userId = tokenInfo.getId();
        session.getAttributes().put(WS_SESSION_ATTR_USER_ID_KEY, userId);
        wsConnectionManager.addSession(userId, session);

        // 新连接建立后，通知客户端拉取最新消息
        AppWSMessage appWSMessage = new AppWSMessage();
        appWSMessage.setType(AppWSMessageTypeEnum.NEW_MSG.getTypeName());
        wsConnectionManager.sendMessage(userId, new TextMessage(JSON.toJSONString(appWSMessage)));
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        Object userIdObj = session.getAttributes().get(WS_SESSION_ATTR_USER_ID_KEY);
        if (userIdObj instanceof Long userId) {
            wsConnectionManager.removeSession(userId, session);
        }
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        try {
            log.info("message:{}", message.getPayload());
            AppWSMessage appWSMessage = JSON.parseObject(message.getPayload(), AppWSMessage.class);
            TextMessageProcessor textMessageProcessor = textMessageProcessorMap.get(appWSMessage.getType());
            if (textMessageProcessor != null) {
                textMessageProcessor.process(session, message, appWSMessage);
            }
        } catch (JSONException ex) {
            log.error("消息格式解析错误:{}", message.getPayload());
            log.error("ex:", ex);
        }
    }

    @Override
    protected void handlePongMessage(WebSocketSession session, PongMessage message) throws Exception {
        log.info("message:{}", message.getPayload());
        super.handlePongMessage(session, message);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        log.info("textMessageProcessorList.size:{}", CollectionUtils.size(textMessageProcessorList));
        if (CollectionUtils.isNotEmpty(textMessageProcessorList)) {
            for (TextMessageProcessor textMessageProcessor : textMessageProcessorList) {
                textMessageProcessorMap.put(textMessageProcessor.getType(), textMessageProcessor);
            }
        }
    }
}
